package stz.flash.main.strobe.model;

import net.rim.device.api.system.Backlight;
import stz.flash.main.FlashKeyEvent;
import stz.flash.main.FlashTimer;
import stz.flash.main.ScreenHandle;
import stz.flash.option.strobe.StrobeOption;
import util.DjDoneListener;

public class Strobe {
	
	private Strobe() {}
	
	public static void toggleStrobeFlash(){
		ToggleStrobeFlash.toggleStrobeFlash();
	}
	
	public static void toggleNormalFlash() {
		
		ToggleNormalFlash.toggleNormalFlash();
	}

	public static Thread getThread() {
		return ToggleStrobeFlash.getThread();
	}
}

/**
 * ---------------------------------------------------
 * Strobe의 기본 플래시 상태에 대해서...
 * 
 * @param ToggleNormalFlash
 *  이 클래스에서만 Strobe의 기본 플래시 상태를 변경해서 옵션에 저장 할 수 있음
 * 
 * @param ToggleStrobeFlash
 *  기본플래시 상태를 참조해서 space로 컨트롤하기만 함
 * ----------------------------------------------------
 *
 * @param working 
 *  StrobeThread가 작동중일때 True상태임
 * 
 * @param toggleFlag 
 *  StrobeThread의 start, interrupt를 무작위로 반복하면 예기치못한 에러가 
 *  많이 발생하기에 같은 동작이 2번 연속으로 실행되지 않도록 flag를 두었음 
 */
class ToggleStrobeFlash{
	
	private static final ScreenHandle screenHandle = ScreenHandle.getIns();
	private static final StrobeOption strobeOption = StrobeOption.getIns();
	private static Thread strobeThread;
	private static Thread lockScreenThread;
	
	private static boolean flashState;
	
	private static boolean working = false;
	private static boolean toggleFlag = false;

	public static synchronized void toggleStrobeFlash(){

		if (working == false && toggleFlag == false) {
			
			working = true;
			toggleFlag = true;

			startStrobeThread();
			
		} else if (working == true && toggleFlag == true) {

			toggleFlag = false;

			interruptThread();
		}
	}
	
	/**
	 * strobe thread 를 생성하고 시작하는 메서드
	 */
	private static void startStrobeThread() {
		strobeThread = new ThreadA();
		strobeThread.start();
	}
	
	/**
	 * strobe thread 를 중단시키는 메서드
	 */
	private static void interruptThread() {
		if (strobeThread == null || strobeThread.isAlive() == false)
			return;
		strobeThread.interrupt();
	}
	
	/**
	 * strobe 의 정보를 외부로 전달해주는 메서드들 
	 */
	public static Thread getThread() {
		if (strobeThread == null)
			strobeThread = new Thread();
		return strobeThread;
	}
	
	public static boolean isFlashEnable(){
		return flashState;
	}
	
	public static void setFlashEnable(boolean enable){
		flashState = enable;
	}
	
	/**
	 * strobe 의 핵심 기능을 담긴 thread class
	 */
	static class ThreadA extends Thread {
		
		public void run() {
			try {
				
				try {
					VRController.runVideoRecorder(null);

					FlashTimer.getIns().stop(FlashTimer.STOP, null);
					
					startThreadOfLockBacklight();
					
					updateTempFlashStateWithInspectVRFlash();
				
					startBlinkLoop();

				} finally {

					finallyStrobeFlash(); 
					
				}
			} catch (InterruptedException e) {
			}
		}
		
		private void updateTempFlashStateWithInspectVRFlash() {

				screenHandle.popScreen();
				
				InspectVRFlash.waitVisibleVR();
				
				flashState = InspectVRFlash.isFlashState();
		}
		
		private void startThreadOfLockBacklight() {
			lockScreenThread = new Thread() {
				public void run() {
					try {
						
						while(true) {
							
							Backlight.enable(true, Backlight.getTimeoutDefault());
							Thread.sleep(Backlight.getTimeoutDefault() - 5);
							
							if (strobeThread.isAlive() == false) 
								return;
						}	
					} catch (InterruptedException e) {
					}
				}
			};
			lockScreenThread.start();
		}
		
		private void startBlinkLoop() throws InterruptedException {
			while (true) {
				if (strobeThreadStopSituation()) {
					toggleFlag = false;
					return;
				}
				blink();
			}
		}
		private boolean strobeThreadStopSituation() {
			return VRController.isVRForeground() == false || screenHandle.isDisplayed();
		}
		
		private void finallyStrobeFlash() throws InterruptedException {
			
			lockScreenThread.interrupt();
			
			VRController.runVideoRecorder(new DjDoneListener() {
			
				public void done() {
					
					VRFlashController.applyVRFlashStateOfOption();//pushScreen도 됨
					FlashTimer.getIns().stopAndStart(FlashTimer.STOP_AND_START_strobe_mode_change_listener);
					
					working = false;
				}

			});
		}
		
		/**
		 * 한번 깜빡이게 하는 메서드 
		 */
		private static void blink() throws InterruptedException {
		
			FlashKeyEvent.postSpaceKey();
			if (flashState) {
				Thread.sleep(getOffTime());
			} else {
				Thread.sleep(getOnTime());
			}
			flashState ^= true;
		}
		
		private static int getOnTime(){
			return strobeOption.getOnTime().intValue();
		}
		
		private static int getOffTime(){
			return strobeOption.getTimeInterval().intValue() - getOnTime();
		}
	}
}


class ToggleNormalFlash {
	
	private static Object lock = new Object();

	public static void toggleNormalFlash() {

		synchronized (lock) {

			runVideoRecorder();

			popScreen();

			ctrlVRFlash(new DjDoneListener() {//pushScreen포함됨

				public void done() {

					synchronized (lock) {
						
						startTimer();

						setFlashState();
					}
				}
			});
		}
	}

	private static void ctrlVRFlash(final DjDoneListener doneListener) {

		new Thread() {
			public void run() {

				VRFlashController.reverseAndApplyVRFlashStateOfOption();
				doneListener.done();
			}
		}.start();
	}

	private static void runVideoRecorder(){
		VRController.runVideoRecorder(null);
	}
	
	private static void popScreen() {
		ScreenHandle.getIns().popScreen();
	}
	
	private static void startTimer() {
		FlashTimer.getIns().stopAndStart(FlashTimer.STOP_AND_START_strobe_mode_change_listener);
	}
	
	private static void setFlashState() {
		if (ToggleStrobeFlash.isFlashEnable() == true)
			ToggleStrobeFlash.setFlashEnable(false);
		else
			ToggleStrobeFlash.setFlashEnable(true);
	}
}
